package com.qinglei.recoup.system.manager;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.qinglei.recoup.common.domain.CommonConstant;
import com.qinglei.recoup.common.domain.RadarMessage;
import com.qinglei.recoup.common.domain.RadarUserDataDTO;
import com.qinglei.recoup.common.domain.RadarUserDataFour;
import com.qinglei.recoup.common.exception.RedisConnectException;
import com.qinglei.recoup.common.service.RedisService;
import com.qinglei.recoup.system.dao.BedHealthStateMapper;
import com.qinglei.recoup.system.dao.BedMapper;
import com.qinglei.recoup.system.domain.*;
import com.qinglei.recoup.system.enums.EventEnum;
import com.qinglei.recoup.system.pojo.BedMonitorTimeVO;
import com.qinglei.recoup.system.pojo.BedStatusVO;
import com.qinglei.recoup.system.service.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;

/**
 * 呼吸心跳报警，封装3.0 协议呼吸、心跳报警
 */
@Component
@Slf4j
public class BreathHeartAlarmV4 {

    @Autowired
    private BedMapper bedMapper;

    @Autowired
    private BedHealthStateMapper bedHealthStateMapper;

    @Autowired
    private BedHealthBreathDailyDataService bedHealthBreathDailyDataService;

    @Autowired
    private RedisService redisService;

    @Value("${Health.v4BreathLow}")
    private Integer v4BreathLow;

    @Value("${Health.v4BreathHight}")
    private Integer v4BreathHight;

    @Value("${Health.v4HeartLow}")
    private Integer v4HeartLow;

    @Value("${Health.v4HearthHight}")
    private Integer v4HearthHight;

    @Value("${Health.v4BreathTimeSsecond}")
    private Integer v4BreathTimeSsecond;

    @Value("${Health.v4HeartTimeSsecond}")
    private Integer v4HeartTimeSsecond;

    @Value("${Health.Th_Amp_Apnea}")
    private Double Th_Amp_Apnea;

    @Value("${Health.Th_Time_Apnea}")
    private Integer Th_Time_Apnea;


    private boolean isV4BreathLow = true;


    private boolean isV4BreathHight = true;


    private boolean isV4HeartLow = true;


    private boolean isV4HearthHight = true;


    @Autowired
    private VitalSignsAlarmService vitalSignsAlarmService;

    public Integer getAlarmNumber(String type, String bedId) throws RedisConnectException {
        if (redisService.get(type + "-" + bedId) != null) {
            return Integer.valueOf(redisService.get(type + "-" + bedId));
        }
        return 0;
    }


    public void setParmas(Bed bed) throws RedisConnectException {
        //1.离床过久2.跌倒3.呼吸过速4.呼吸暂停过久5.心跳过缓6.心跳过速

        //呼吸过速
        String breathHightKey = "VitalSignsAlarm-" + bed.getTenantId() + "-3";
        VitalSignsAlarm vitalSignsAlarm = vitalSignsAlarmService.getVitalSignsAlarm(breathHightKey);
        if(!Objects.isNull(vitalSignsAlarm)){
            String v4BreathHightStr = vitalSignsAlarm.getBpm();
            if (StringUtils.isNotBlank(v4BreathHightStr)) {
                v4BreathHight = Integer.parseInt(v4BreathHightStr);
            }

            String v4BreathTimeSsecondStr = vitalSignsAlarm.getContinued();
            if (StringUtils.isNotBlank(v4BreathTimeSsecondStr)) {
                v4BreathTimeSsecond = Integer.parseInt(v4BreathTimeSsecondStr);
            }

            if (vitalSignsAlarm.getEnable() == 0) {
                isV4BreathHight = false;
            } else {
                isV4BreathHight = true;
            }
        }
        //呼吸暂停过久
        String breathLowKey = "VitalSignsAlarm-" + bed.getTenantId() + "-4";
        VitalSignsAlarm vitalSignsAlarm01 = vitalSignsAlarmService.getVitalSignsAlarm(breathLowKey);
        if(!Objects.isNull(vitalSignsAlarm01)){
            String Th_Amp_ApneaStr = vitalSignsAlarm01.getBpm();
            if (StringUtils.isNotBlank(Th_Amp_ApneaStr)) {
                Th_Amp_Apnea = Double.parseDouble(Th_Amp_ApneaStr);
            }

            String Th_Time_ApneaStr = vitalSignsAlarm01.getContinued();
            if (StringUtils.isNotBlank(Th_Time_ApneaStr)) {
                Th_Time_Apnea = Integer.parseInt(Th_Time_ApneaStr);
            }

            if (vitalSignsAlarm01.getEnable() == 0) {
                isV4BreathLow = false;
            } else {
                isV4BreathLow = true;
            }
        }
        //心跳过缓
        String heartLowKey = "VitalSignsAlarm-" + bed.getTenantId() + "-5";
        VitalSignsAlarm vitalSignsAlarm02 = vitalSignsAlarmService.getVitalSignsAlarm(heartLowKey);
        if(!Objects.isNull(vitalSignsAlarm02)){
            String v4HeartLowStr = vitalSignsAlarm02.getBpm();
            if (StringUtils.isNotBlank(v4HeartLowStr)) {
                v4HeartLow = Integer.parseInt(v4HeartLowStr);
            }

            String v4HeartTimeSsecondStr = vitalSignsAlarm01.getContinued();
            if (StringUtils.isNotBlank(v4HeartTimeSsecondStr)) {
                v4HeartTimeSsecond = Integer.parseInt(v4HeartTimeSsecondStr);
            }

            if (vitalSignsAlarm02.getEnable() == 0) {
                isV4HeartLow = false;
            } else {
                isV4HeartLow = true;
            }
        }

        //心跳过速
        String heartHightKey = "VitalSignsAlarm-" + bed.getTenantId() + "-6";
        VitalSignsAlarm vitalSignsAlarm03 = vitalSignsAlarmService.getVitalSignsAlarm(heartHightKey);
        if(!Objects.isNull(vitalSignsAlarm03)){
            String v4HearthHightStr = vitalSignsAlarm03.getBpm();
            if (StringUtils.isNotBlank(v4HearthHightStr)) {
                v4HearthHight = Integer.parseInt(v4HearthHightStr);
            }


            String v4HeartTimeSsecondStr1 = vitalSignsAlarm01.getContinued();
            if (StringUtils.isNotBlank(v4HeartTimeSsecondStr1)) {
                int v4HeartTimeSsecond1 = Integer.parseInt(v4HeartTimeSsecondStr1);
            }


            if (vitalSignsAlarm03.getEnable() == 0) {
                isV4HearthHight = false;
            } else {
                isV4HearthHight = true;
            }
        }

    }

    /**
     * 记录呼吸、心跳异常事件
     *
     * @param message
     */
    public void updateBreathStatus(RadarMessage message) {

        synchronized (this) {
            RadarUserDataFour data = (RadarUserDataFour) message.getData();
            //目标过近标志 1 表示过近，0 表示正常
            Integer TCFg = data.getTCFg();
            //离床标志 1 表示离床，0 表示在床
            Integer OBFg = data.getOBFg();
            //1 表示配合，0 表示非配合
            Integer TSFg = data.getTSFg();
            Bed bed = bedMapper.selectBySn(message.getSn());
            if (bed == null) {
                log.debug("procRadarData not bind bed sn: {}", message.getSn());
                return;
            }
            //如果事件报警或者在离床状态
            if (bed.getStatus() == 2 || bed.getSubStatus() == 1) {
                return;
            }
            //距离正常且离床
            if (TCFg == 0 && OBFg == 1) {
                return;
            }
            //获取WEB端设置的预值，没有的话就取配置文件中的
            try {
                setParmas(bed);
            } catch (RedisConnectException e) {
                e.printStackTrace();
            }
            //非配合或者目标距离过近
            if (TSFg == 0 || TCFg == 1) {
                addNesynapsis(bed.getId());
                return;
            }
            //移除非配合次数计数
            removeNesynapsis(bed.getId());
            //呼吸BPM估计值
            Integer breathBpm = data.getBrebp();
            //心率BPM估计值
            Integer heartBpm = data.getHRBpRe();
            //呼吸深度
            double bdef = data.getBdef();
            String bedId = String.valueOf(bed.getId());

            QueryWrapper queryWrapper = new QueryWrapper();
            queryWrapper.eq("bed_id", bedId);
            List<BedHealthState> bedHealthStates = bedHealthStateMapper.selectList(queryWrapper);
            //根据床位ID查询健康报警事件表中是否存在值
            boolean isHeaythAlrem = (bedHealthStates != null && bedHealthStates.size() > 0);
            //呼吸深度大于等于呼吸过缓的阈值比并且呼吸BPM小于等于心跳最高值
            boolean breathAlarm = (bdef >= Th_Amp_Apnea && breathBpm <= v4BreathHight);
            //心率BPM大于等于心跳最低阈值并且心跳BPM小于等于心跳最高值
            boolean hearthAlarm = (heartBpm >= v4HeartLow && heartBpm <= v4HearthHight);
            //查看是否在检测时间段内并且没有监测仪非离线、非关闭或者非报警
            boolean isMonitorTime = bedService.isMonitorTime(bed.getId());

            try {
                //心跳BPM最高数据队列
                Integer HEART_BPM_HIGHT_NUM = getAlarmNumber(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedId);
                //心跳BPM最低数据队列
                Integer HEART_BPM_LOW = getAlarmNumber(CommonConstant.HEART_BPM_LOW_TIME_START, bedId);
                //心跳BPM最高数据队列不等于空并且大于0并且大于心跳预值的最高值
                boolean HEART_BPM_HIGHT_flg = HEART_BPM_HIGHT_NUM != null && HEART_BPM_HIGHT_NUM > 0 && heartBpm > v4HearthHight;
                //心跳BPM最低数据队列不为空并且大于0并且小于最低的阈值
                boolean HEART_BPM_LOW_flg = HEART_BPM_LOW != null && HEART_BPM_LOW > 0 && heartBpm < v4HeartLow;
                //如果呼吸BPM大于设定的最高值并且报警表中没有数据并且在检测时间段内、未关闭、未报警
                if (breathBpm > v4BreathHight && !isHeaythAlrem && isV4BreathHight && isMonitorTime) {
                    //删除呼吸BPM最低数据队列
                    removeKey(CommonConstant.BREATH_BPM_LOW_TIME_START, bedId);
                    //心跳BPM小于心跳预最高值，那么就删除心跳BPM最高数据队列
                    if (!HEART_BPM_HIGHT_flg) {
                        removeKey(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedId);
                    }
                    //心跳BPM最低数据大于最低阀值，那么删除最低数据队列
                    if (!HEART_BPM_LOW_flg) {
                        removeKey(CommonConstant.HEART_BPM_LOW_TIME_START, bedId);
                    }
                    //添加呼吸BPM最高数据队列,并且如异常库，推送消息
                    addKey(CommonConstant.BREATH_BPM_HIGHT_TIME_START, bedId);
                    return;
                } else if (breathAlarm && hearthAlarm) {
                    processingDataBreath(bed);
                }
                if (bdef < Th_Amp_Apnea && !isHeaythAlrem && isV4BreathLow && isMonitorTime) {
                    removeKey(CommonConstant.BREATH_BPM_HIGHT_TIME_START, bedId);
//                    removeKey(CommonConstant.HEART_BPM_LOW_TIME_START, bedId);
//                    removeKey(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedId);
                    if (!HEART_BPM_HIGHT_flg) {
                        removeKey(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedId);
                    }
                    if (!HEART_BPM_LOW_flg) {
                        removeKey(CommonConstant.HEART_BPM_LOW_TIME_START, bedId);
                    }
                    addKey(CommonConstant.BREATH_BPM_LOW_TIME_START, bedId);
                    return;
                }

                if (heartBpm > v4HearthHight && !isHeaythAlrem && isV4HearthHight && isMonitorTime) {
                    removeKey(CommonConstant.HEART_BPM_LOW_TIME_START, bedId);
                    removeKey(CommonConstant.BREATH_BPM_LOW_TIME_START, bedId);
                    removeKey(CommonConstant.BREATH_BPM_HIGHT_TIME_START, bedId);
                    addKey(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedId);
                    return;
                } else if (breathAlarm && hearthAlarm) {
                    processingDataHeaart(bed);
                }
                if (heartBpm < v4HeartLow && !isHeaythAlrem && isV4HeartLow && isMonitorTime) {
                    removeKey(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedId);
                    removeKey(CommonConstant.BREATH_BPM_LOW_TIME_START, bedId);
                    removeKey(CommonConstant.BREATH_BPM_HIGHT_TIME_START, bedId);
                    addKey(CommonConstant.HEART_BPM_LOW_TIME_START, bedId);
                    return;

                }

            } catch (RedisConnectException ex) {
                log.debug("RedisConnectException : {}", ex.fillInStackTrace());
                return;
            }
        }
    }

    private void removeNesynapsis(Integer id) {
        try {
            redisService.del("Nesynapsis" + "-" + id);
        } catch (Exception ex) {
            log.error(ex.getMessage());
        }
    }

    @Autowired
    private BedService bedService;
    @Autowired
    private EventWsService eventWsService;
    @Autowired
    private EventLogService eventLogService;

    @Autowired
    private EventProcService eventProcService;

    @Autowired
    private BuildingService buildingService;

    private void addNesynapsis(Integer id) {
        try {
            if (redisService.get("Nesynapsis" + "-" + id) == null) {
                redisService.set("Nesynapsis" + "-" + id, "1");
            } else {
                redisService.incr("Nesynapsis" + "-" + id);
                Integer nesynapsisNum = Integer.valueOf(redisService.get("Nesynapsis" + "-" + id));
                QueryWrapper queryWrapper = new QueryWrapper();
                queryWrapper.eq("bed_id", id);
                List<BedHealthState> bedHealthStates = bedHealthStateMapper.selectList(queryWrapper);
                boolean isHeaythAlrem = (bedHealthStates != null && bedHealthStates.size() > 0);
                if (nesynapsisNum == 6) {
                    BedRadarBO bedRadarBO = bedService.getBedWithSn(id);
                    //推送日志消息
                    if (isHeaythAlrem) {
                        EventLog eventLog = new EventLog();
                        eventLog.setBedId(bedRadarBO.getId());
                        eventLog.setEventId(0l);
                        eventLog.setContent("用户动作有点大");
                        eventLog.setTenantId(bedRadarBO.getTenantId());
                        eventLog.setCreateTime(LocalDateTime.now());
                        eventLog.setType(32);
                        eventLog.setName(getBedName(bedRadarBO.getId()));
                        eventLog.setTypeGroup(EventEnum.TYPE_MONITOR_TIME);
                        eventWsService.pushEventMsg(eventLog);
                        eventLogService.save(eventLog);
                    }


                    Building building = buildingService.getById(bedRadarBO.getBuildingId());
                    BedStatusVO bedStatusVO = new BedStatusVO();
                    bedStatusVO.setBedId(bedRadarBO.getId());
                    bedStatusVO.setBedName(getBedName(bedRadarBO.getId()));
                    if (building != null) {
                        bedStatusVO.setBuildingName(building.getName());
                    }
                    bedStatusVO.setStatus(bedRadarBO.getStatus());
                    bedStatusVO.setStatusName(getStatusName(bedRadarBO.getStatus(), bedRadarBO.getSubStatus()));
                    bedStatusVO.setSubStatus(bedRadarBO.getSubStatus());
                    //bedStatusVO.setHealthyBpm();//类型
                    //bedStatusVO.setHealthyStatusName();//名称
                    bedStatusVO.setEventId(0l);
                    bedStatusVO.setRadarType(1);
                    bedStatusVO.setMissedEventNum(eventProcService.getMissedEventNumByBed(id));
                    BedMonitorTimeVO bedMonitorTimeVO = bedService.getBedCurMonitorTime(bedRadarBO.getId());
                    if (bedMonitorTimeVO != null) {
                        bedStatusVO.setCurMonitorTime(bedMonitorTimeVO.getStartTime() + '-' + bedMonitorTimeVO.getEndTime());
                    }
                    eventWsService.pushBedStatusMsg(bedStatusVO);
                    clearAlearm(id);
                }

            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }


    private String getStatusName(Integer status, Integer SubStatus) {
        String resultStr = new String();
        if (status == 1) {
            switch (SubStatus) {
                case 1:
                    resultStr = "离床";
                    break; //可选
                case 2:
                    resultStr = "在床";
                    //resultStr = "清醒";
                    break; //可选
                case 3:
                    resultStr = "在床";
                    //resultStr = "浅睡";
                    break; //可选
                case 4:
                    //resultStr = "深睡";
                    resultStr = "在床";
                    break; //可选
                case 5:
                    resultStr = "无人";
                    break; //可选
                case 6:
                    resultStr = "有人";
                    break; //可选
                default: //可选
                    //语句
            }
        } else if (status == 2) {
            switch (SubStatus) {
                case 1:
                    resultStr = "离床";
                    break; //可选
                case 2:
                    resultStr = "跌倒";
                    break; //可选
                default: //可选
                    //语句
            }
        }

        return resultStr;
    }

    private String getBedName(Integer bedId) {
        BedBO bedFullName = bedService.getBedFullName(bedId);
        String name = "";
        if (bedFullName != null) {
            name = bedFullName.getBuildingName() + "-" + bedFullName.getFloorName() + "-" + bedFullName.getRoomName()
                    + "-" + bedFullName.getBedName();
        }
        return name;
    }

    /**
     * 新增键值对
     *
     * @param type
     * @param bedId
     * @throws RedisConnectException
     */
    private void addKey(String type, String bedId) throws RedisConnectException {
        if (redisService.get(type + "-" + bedId) == null) {
            redisService.set(type + "-" + bedId, "1");
        } else {

            redisService.incr(type + "-" + bedId);
            Integer alarmNumber = Integer.valueOf(redisService.get(type + "-" + bedId));
            //是呼吸BPM最高数据队列并且次数达到了设定的最高阀值次数
            if (type.equals(CommonConstant.BREATH_BPM_HIGHT_TIME_START)) {
                if (alarmNumber == v4BreathTimeSsecond + 1) {
                    bedHealthBreathDailyDataService.breathBpmHight(bedId);
                    redisService.del(type + "-" + bedId);
                }
            } else if (type.equals(CommonConstant.BREATH_BPM_LOW_TIME_START)) {
                if (alarmNumber == Th_Time_Apnea + 1) {
                    bedHealthBreathDailyDataService.breathBpmLow(bedId);
                    redisService.del(type + "-" + bedId);
                }
            } else if (type.equals(CommonConstant.HEART_BPM_HIGHT_TIME_START)) {
                if (alarmNumber == v4HeartTimeSsecond + 1) {
                    bedHealthBreathDailyDataService.heartBpmHight(bedId);
                    redisService.del(type + "-" + bedId);
                }
            } else if (type.equals(CommonConstant.HEART_BPM_LOW_TIME_START)) {
                if (alarmNumber == v4HeartTimeSsecond + 1) {
                    bedHealthBreathDailyDataService.heartBpmLow(bedId);
                    redisService.del(type + "-" + bedId);
                }
            }
        }
    }

    /**
     * 删除键值对
     *
     * @param type
     * @param bedId
     * @throws RedisConnectException
     */
    private void removeKey(String type, String bedId) throws RedisConnectException {
        if (redisService.get(type + "-" + bedId) != null) {
            redisService.del(type + "-" + bedId);
        }


    }


    public void processingDataBreath(Bed bed) throws RedisConnectException {
        String bedId = String.valueOf(bed.getId());
        //正常
        String breathBpmNomalFlag = redisService.get(CommonConstant.BREATH_BPM_NOMAL + bedId);
        removeKey(CommonConstant.BREATH_BPM_HIGHT_TIME_START, bedId);
        removeKey(CommonConstant.BREATH_BPM_LOW_TIME_START, bedId);
        if (breathBpmNomalFlag == null) {
            redisService.set(CommonConstant.BREATH_BPM_NOMAL + bedId, CommonConstant.BREATH_BPM_NOMAL);
            bedHealthBreathDailyDataService.processingDataRecovery(bed, BedHealthState.SUB_STATUS_BREATH_NORMAL, EventEnum.ALARM_BREATH_BPM_NORMAL.getCode(), EventEnum.ALARM_BREATH_BPM_NORMAL.getContent());
        }
    }

    public void processingDataHeaart(Bed bed) throws RedisConnectException {
        String bedId = String.valueOf(bed.getId());
        String heattBpmNomalFlag = redisService.get(CommonConstant.HEART_BPM_NOMAL + bedId);
        removeKey(CommonConstant.HEART_BPM_LOW_TIME_START, bedId);
        removeKey(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedId);
        if (heattBpmNomalFlag == null) {
            redisService.set(CommonConstant.HEART_BPM_NOMAL + bedId, CommonConstant.HEART_BPM_NOMAL);
            bedHealthBreathDailyDataService.processingDataRecovery(bed, BedHealthState.SUB_STATUS_HEART_NORMAL, EventEnum.ALARM_HEART_BPM_NORMAL.getCode(), EventEnum.ALARM_HEART_BPM_NORMAL.getContent());
        }
    }

    public void clearAlearm(Integer bedId) {
        String bedIdstr = String.valueOf(bedId);
        try {
            removeKey(CommonConstant.BREATH_BPM_HIGHT_TIME_START, bedIdstr);
            removeKey(CommonConstant.BREATH_BPM_LOW_TIME_START, bedIdstr);
            removeKey(CommonConstant.HEART_BPM_LOW_TIME_START, bedIdstr);
            removeKey(CommonConstant.HEART_BPM_HIGHT_TIME_START, bedIdstr);
            redisService.set(CommonConstant.BREATH_BPM_NOMAL + bedId, CommonConstant.BREATH_BPM_NOMAL);
            redisService.set(CommonConstant.HEART_BPM_NOMAL + bedId, CommonConstant.HEART_BPM_NOMAL);
        } catch (RedisConnectException e) {
            e.fillInStackTrace();
        }
        QueryWrapper queryWrapperHight = new QueryWrapper();
        queryWrapperHight.eq("bed_id", bedId);
        bedHealthStateMapper.delete(queryWrapperHight);
    }

}

